#include "napi/native_api.h"
#include <vector>

#include <unistd.h>
#include <sys/types.h>

#ifdef __cplusplus
extern "C" {
#endif

#include <arkui/native_node_napi.h>
#include <arkui/native_node.h>
#include <arkui/native_type.h>
#include <arkui/native_interface.h>

#include <hilog/log.h>

#define LOG_TAG "CAPI_DEMO"

#ifdef __cplusplus
}
#endif
static napi_value Add(napi_env env, napi_callback_info info)
{
    size_t argc = 2;
    napi_value args[2] = {nullptr};

    napi_get_cb_info(env, info, &argc, args , nullptr, nullptr);

    napi_valuetype valuetype0;
    napi_typeof(env, args[0], &valuetype0);

    napi_valuetype valuetype1;
    napi_typeof(env, args[1], &valuetype1);

    double value0;
    napi_get_value_double(env, args[0], &value0);

    double value1;
    napi_get_value_double(env, args[1], &value1);

    napi_value sum;
    napi_create_double(env, value0 + value1, &sum);

    return sum;

}

ArkUI_NodeContentHandle contentHandle;
ArkUI_NativeNodeAPI_1 *arkUINativeNodeApi;
std::vector<ArkUI_NodeHandle> nodes;

static char *userData = "Butten Data";
static char *userTData = "Text Data";
static void ButtenEventReceiver(ArkUI_NodeEvent* event)
{
    OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, LOG_TAG, "ButtenEventReceiver thread id: %{public}d", (int)gettid());
    OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, LOG_TAG, "ButtenEventReceiver target id: %{public}d", OH_ArkUI_NodeEvent_GetTargetId(event));
    OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, LOG_TAG, "ButtenEventReceiver event id: %{public}d", OH_ArkUI_NodeEvent_GetEventType(event));
    OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, LOG_TAG, "ButtenEventReceiver event userData: %{public}s", (char *)OH_ArkUI_NodeEvent_GetUserData(event));
    ArkUI_NodeComponentEvent *nodeComponentEvent = OH_ArkUI_NodeEvent_GetNodeComponentEvent(event);
    if (!nodeComponentEvent) {
        return;
    }

//     OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, LOG_TAG, "nodeComponentEvent Nx: %{public}f", nodeComponentEvent->data[0]);
//     OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, LOG_TAG, "nodeComponentEvent Ny: %{public}f", nodeComponentEvent->data[1]);
//     OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, LOG_TAG, "nodeComponentEvent timeStamp: %{public}f", nodeComponentEvent->data[2]);
//     OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, LOG_TAG, "nodeComponentEvent type: %{public}d", nodeComponentEvent->data[3]);
//     OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, LOG_TAG, "nodeComponentEvent WX: %{public}f", nodeComponentEvent->data[4]);
//     OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, LOG_TAG, "nodeComponentEvent WY: %{public}f", nodeComponentEvent->data[5]);
//     OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, LOG_TAG, "nodeComponentEvent SX: %{public}f", nodeComponentEvent->data[6]);
//     OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, LOG_TAG, "nodeComponentEvent SY: %{public}f", nodeComponentEvent->data[7]);
}
static void EventReceiver(ArkUI_NodeEvent* event)
{
    OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, LOG_TAG, "EventReceiver thread id: %{public}d", (int)gettid());
    OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, LOG_TAG, "EventReceiver target id: %{public}d", OH_ArkUI_NodeEvent_GetTargetId(event));
    OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, LOG_TAG, "EventReceiver event id: %{public}d", OH_ArkUI_NodeEvent_GetEventType(event));
    OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, LOG_TAG, "EventReceiver event userData: %{public}s", (char *)OH_ArkUI_NodeEvent_GetUserData(event));
}

static void EventReceiver2(ArkUI_NodeEvent* event)
{
    OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, LOG_TAG, "EventReceiver2 thread id: %{public}d", (int)gettid());
    OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, LOG_TAG, "EventReceiver2 target id: %{public}d", OH_ArkUI_NodeEvent_GetTargetId(event));
    OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, LOG_TAG, "EventReceiver2 event id: %{public}d", OH_ArkUI_NodeEvent_GetEventType(event));
    OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, LOG_TAG, "EventReceiver2 event userData: %{public}s", (char *)OH_ArkUI_NodeEvent_GetUserData(event));
}

static napi_value AddBNode(napi_env env, napi_callback_info info)
{
    // 设置属性
    OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, LOG_TAG, "AddBNode thread id: %{public}d", (int)gettid());
    ArkUI_NodeHandle nodeHandle = arkUINativeNodeApi->createNode(ARKUI_NODE_BUTTON);
    ArkUI_NumberValue valuew[] = {{.f32 = 0.5}};
    ArkUI_AttributeItem itemW = {valuew, 1};
    arkUINativeNodeApi->setAttribute(nodeHandle, NODE_WIDTH_PERCENT, &itemW); // 只记录的itemW的地址，如果ArkUI_AttributeItem 数据不一样，不可以重复使用
    ArkUI_NumberValue valueh[] = {{.f32 = 0.05}};
    ArkUI_AttributeItem itemH = {valueh, 1};
    arkUINativeNodeApi->setAttribute(nodeHandle, NODE_HEIGHT_PERCENT, &itemH);

    ArkUI_AttributeItem text = {nullptr, 0, "中文 CButton"};
    arkUINativeNodeApi->setAttribute(nodeHandle, NODE_BUTTON_LABEL, &text);
    ArkUI_NumberValue fontsize[] = {{.f32 = 20}};
    ArkUI_AttributeItem font = {fontsize, 1};
    arkUINativeNodeApi->setAttribute(nodeHandle, NODE_FONT_SIZE, &font);
    ArkUI_NumberValue marginvp[] = {{.f32 = 5}, {.f32 = 5}, {.f32 = 5}, {.f32 = 5},};
    ArkUI_AttributeItem margin = {marginvp, 4};
    arkUINativeNodeApi->setAttribute(nodeHandle, NODE_MARGIN, &margin);

    // 绑定回调
    arkUINativeNodeApi->addNodeEventReceiver(nodeHandle, EventReceiver);  // ButtenEventReceiver
    arkUINativeNodeApi->registerNodeEvent(nodeHandle, NODE_ON_CLICK, nodes.size(), userData);
//     arkUINativeNodeApi->registerNodeEvent(nodeHandle, NODE_TOUCH_EVENT, nodes.size(), nullptr);
//     arkUINativeNodeApi->registerNodeEventReceiver(EventReceiver);
    // 挂载显示
    OH_ArkUI_NodeContent_AddNode(contentHandle, nodeHandle);
    
    nodes.push_back(nodeHandle);
    OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, LOG_TAG, "nodes.size : %{public}ld", nodes.size());
    return nullptr;
}

static napi_value AddTNode(napi_env env, napi_callback_info info)
{
    // 设置属性
    OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, LOG_TAG, "AddTNode thread id: %{public}d", (int)gettid());
    ArkUI_NodeHandle nodeHandle = arkUINativeNodeApi->createNode(ARKUI_NODE_TEXT);
    ArkUI_NumberValue valuew[] = {{.f32 = 0.5}};
    ArkUI_AttributeItem itemW = {valuew, 1};
    arkUINativeNodeApi->setAttribute(nodeHandle, NODE_WIDTH_PERCENT, &itemW); // 只记录的itemW的地址，如果ArkUI_AttributeItem 数据不一样，不可以重复使用
    ArkUI_NumberValue valueh[] = {{.f32 = 0.05}};
    ArkUI_AttributeItem itemH = {valueh, 1};
    arkUINativeNodeApi->setAttribute(nodeHandle, NODE_HEIGHT_PERCENT, &itemH);

    ArkUI_AttributeItem text = {nullptr, 0, "中文 CText"};
    arkUINativeNodeApi->setAttribute(nodeHandle, NODE_TEXT_CONTENT, &text);
    ArkUI_NumberValue fontsize[] = {{.f32 = 20}};
    ArkUI_AttributeItem font = {fontsize, 1};
    arkUINativeNodeApi->setAttribute(nodeHandle, NODE_FONT_SIZE, &font);
    ArkUI_NumberValue marginvp[] = {{.f32 = 5}, {.f32 = 5}, {.f32 = 5}, {.f32 = 5},};
    ArkUI_AttributeItem margin = {marginvp, 4};
    arkUINativeNodeApi->setAttribute(nodeHandle, NODE_MARGIN, &margin);

    // 绑定回调
    arkUINativeNodeApi->addNodeEventReceiver(nodeHandle, EventReceiver2); // 对指定的node绑定回调，各个node互不影响
    arkUINativeNodeApi->registerNodeEvent(nodeHandle, NODE_ON_CLICK, nodes.size(), userTData);
//     arkUINativeNodeApi->registerNodeEvent(nodeHandle, NODE_TOUCH_EVENT, nodes.size(), nullptr); // 刷新率太高，使用价值不高
//     arkUINativeNodeApi->registerNodeEventReceiver(EventReceiver2); // 全局回调绑定所有的 node，需要开发者在回调函数中自己识别
    // 挂载显示
    OH_ArkUI_NodeContent_AddNode(contentHandle, nodeHandle);
    
    nodes.push_back(nodeHandle);
    OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, LOG_TAG, "nodes.size : %{public}ld", nodes.size());
    return nullptr;
}

static napi_value InitNativeUI(napi_env env, napi_callback_info info)
{
    size_t argc = 1;
    napi_value args[1] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &contentHandle);
    OH_ArkUI_GetModuleInterface(ARKUI_NATIVE_NODE, ArkUI_NativeNodeAPI_1, arkUINativeNodeApi);

    return nullptr;
}


EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports)
{
    napi_property_descriptor desc[] = {
        { "add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "initNativeUI", nullptr, InitNativeUI, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "addBNode", nullptr, AddBNode, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "addTNode", nullptr, AddTNode, nullptr, nullptr, nullptr, napi_default, nullptr }
    };
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);

    return exports;
}
EXTERN_C_END

static napi_module demoModule = {
    .nm_version = 1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = Init,
    .nm_modname = "entry",
    .nm_priv = ((void*)0),
    .reserved = { 0 },
};

extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
{
    napi_module_register(&demoModule);
}
